@tool
@icon("icons/state_chart.svg")
class_name StateChart
extends Node

const DebuggerRemote = preload("res://addons/State_Chart/util/editor_debugger/editor_debugger_remote.gd")
#region 属性
## 是否被编辑器监视器监测
@export var track_in_editor:bool = false
@export var init_expression_properties:Dictionary = {}
var state:State = null
var expression_properties:Dictionary = {}
var _queued_events:Array[StringName] = []
var _property_change_pending:bool = false
# 是否锁定
var _locked_down:bool = false
var _queued_transitions:Array[Dictionary] = []
var _transition_processing_active:bool = false
var _debugger_remote:DebuggerRemote = null
#endregion
#region 字段
#endregion
#region 信号
signal event_received(event:StringName)
#endregion

#region 基类方法
#endregion
#region 公共方法
func send_event(event:StringName):
	if not is_node_ready():
		push_error("StateChart还没有准备好，如果在_ready中调用send_event，请延迟调用（call_deferred）")
		return
	if not is_instance_valid(state):
		push_error("StateChart没有根State，忽略对send_event的调用")
		return
	_queued_events.append(event)
	_run_changes()
func get_expression_property(key:StringName,default_value:Variant = null) -> Variant:
	return expression_properties.get(key,default_value)
func set_expression_property(key:StringName,value):
	if not is_node_ready():
		await ready
		push_error("StateChart还没有准备好，如果在_ready中调用set_expression_property，请延迟调用（call_deferred）")
		return
	if not is_instance_valid(state):
		push_error("StateChart没有根State，忽略对set_expression_property的调用")
		return
	if value == null:
		expression_properties.erase(key)
		return
	expression_properties[key] = value
	_property_change_pending = true
	_run_changes()
func step():
	if not is_node_ready():
		push_error("StateChart还没有准备好，如果在_ready中调用step，请延迟调用（call_deferred）")
		return
	if not is_instance_valid(state):
		push_error("StateChart没有根State，忽略对step的调用")
		return
	state.state_step()
#endregion
#region 私有方法
func _run_changes():
	if _locked_down:
		return
	_locked_down = true
	while (not _queued_events.is_empty()) or _property_change_pending:
		if _property_change_pending:
			_property_change_pending = false
			state.process_transitions(&"",true)
		if not _queued_events.is_empty():
			var next_event = _queued_events.pop_front()
			event_received.emit(next_event)
			state.process_transitions(next_event,false)
	_locked_down = false
func _run_transition(transition:Transition,source:State):
	if _transition_processing_active:
		_queued_transitions.append({transition : source})
		return
	_transition_processing_active = true
	_do_run_transition(transition,source)
	var execution_count = 1
	while _queued_transitions.size() > 0:
		var next_transition_entry = _queued_transitions.pop_front()
		var next_transition = next_transition_entry.keys()[0]
		var next_transition_source = next_transition_entry[next_transition]
		_do_run_transition(next_transition,next_transition_source)
		execution_count += 1
		if execution_count > 100:
			push_error("在转换中检测到无限循环，已终止，StateChart失效且不再可用")
			break
	_transition_processing_active = false
func _do_run_transition(transition:Transition,source:State):
	if source.active:
		transition.taken.emit()
		source.handle_transition(transition,source)
	else:
		push_warning("忽略从{0}到{1}的状态转换，因为源State不是活动状态，请检查是否在单个帧触发多次状态转换".format([source.name,transition.to]))
#endregion
#region 生命周期函数
func _ready() -> void:
	if Engine.is_editor_hint():
		return
	if init_expression_properties != null:
		for key in init_expression_properties.keys():
			if key is not String or key is not StringName:
				push_error("初始化表达式的Key必须是String或StringName类型，否则会被忽略")
				continue
			expression_properties[key] = init_expression_properties[key]
	state = get_child(0) as State
	state.init()
	state.enter.call_deferred()
	if track_in_editor and OS.has_feature("editor"):
		_debugger_remote = DebuggerRemote.new(self)
func _get_configuration_warnings() -> PackedStringArray:
	var warnings:Array = []
	if get_child_count() != 1:
		warnings.append("StateChart必须且只能有一个子节点")
	elif get_child(0) is not State:
		warnings.append("StateChart的子节点必须是State类型")
	return warnings
#endregion
